package pe.gob.osinergmin.utils;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Environment;
import android.util.Log;
import android.view.Gravity;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import android.widget.Toast;

import com.sromku.simple.storage.SimpleStorage;
import com.sromku.simple.storage.SimpleStorageConfiguration;
import com.sromku.simple.storage.Storage;

import org.apache.http.impl.cookie.DateUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import pe.gob.osinergmin.R;
import pe.gob.osinergmin.bean.SupervisionMovilDetalleSCOP;
import pe.gob.osinergmin.bean.common.Producto;

public class PuntoControlUtils {

    public static String convertFromObjectToJsonString(pe.gob.osinergmin.bean.generic.GenericBean bean, String[] fields) {
        Map<String, Object> data = new HashMap<>();
        for(String field : fields){
            Method[] methods = bean.getClass().getDeclaredMethods();
            Method method = null;
            Object value = null;
            for(Method _method : methods){
                if(_method.getName().toLowerCase().equals("get"+field.toLowerCase())){
                    method = _method;
                    break;
                }
            }
            if(method != null){
                try {
                    value = method.invoke(bean, (Object[]) null);
                } catch (IllegalAccessException | InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
            if(value == null){
                data.put(field, "null");
            }else {
                if (value instanceof String) {
                    data.put(field, JSONObject.quote((String) value));
                } else {
                    if (value instanceof Date) {
                        data.put(field, ((Date) value).getTime());
                    } else {
                        data.put(field, value);
                    }
                }
            }
        }
        JSONObject json = new JSONObject();
        try {
            json.put("class", bean.getClass().getCanonicalName());
            json.put("bean", data);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return json.toString();
    }

    public static String convertFromListToJsonString(List<?> list) {
        List<String> nList = null;
        if(list != null && list.size() > 0){
            nList = new ArrayList<>();
            for(Object item : list){
                nList.add(item.toString());
            }
        }
        JSONArray json = new JSONArray(nList);
        return json.toString();
    }

    public static Object convertFromJsonStringToObject(String jsonstring){
        Object bean = null;
        try {
            if(jsonstring != null && !PuntoControlConstants.EMPTY.equals(jsonstring)){
                JSONObject json = new JSONObject(jsonstring);
                String _class = json.getString("class");
                System.out.println(json.getString("bean"));
                JSONObject _bean = new JSONObject(json.getString("bean"));
                Class _toInstance = Class.forName(_class);

                bean = _toInstance.newInstance();

                Iterator<String> itField = _bean.keys();
                while(itField.hasNext()){
                    String field = itField.next();
                    Class _beanClass = null;
                    if (bean != null) {
                        _beanClass = bean.getClass();
                    }
                    Method[] methods = new Method[0];
                    if (_beanClass != null) {
                        methods = _beanClass.getDeclaredMethods();
                    }
                    Method method = null;
                    Object value = _bean.get(field);
                    for(Method _method : methods){
                        if(_method.getName().toLowerCase().equals("set"+field.toLowerCase())){
                            method = _method;
                            break;
                        }
                    }
                    if(method != null){
                        try {
                            if(!"null".equals(value.toString())){
                                String className = ((Class)(method.getGenericParameterTypes()[0])).getName();
                                if(className.equals(Date.class.getName())){
                                    value = new Date((Long)value);
                                    method.invoke(bean,value);
                                }else{
                                    method.invoke(bean,value);
                                }
                            }
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                            bean = null;
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                            bean = null;
                        }
                    }
                }
            }
        } catch (JSONException e) {
            e.printStackTrace();
            bean = null;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            bean = null;
        } catch (InstantiationException e) {
            e.printStackTrace();
            bean = null;
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            bean = null;
        }
        return bean;
    }

    public static List<?> convertFromJsonStringToList(String jsonstring){
        List<Object> list = null;
        try {
            if(jsonstring != null && !PuntoControlConstants.EMPTY.equals(jsonstring)){
                JSONArray json = new JSONArray(jsonstring);
                list = new ArrayList<>();
                for(int i = 0; i < json.length(); i++){
                    String item = json.getString(i);
                    list.add(convertFromJsonStringToObject(item));
                }
            }
        } catch (JSONException e) {
            e.printStackTrace();
            list = null;
        }
        return list;
    }

    public static Boolean compareObjects(pe.gob.osinergmin.bean.generic.GenericBean original, pe.gob.osinergmin.bean.generic.GenericBean filtro){
        Boolean result = true;
        try {
            if(original != null && filtro != null){
                Class originalClass = original.getClass();
                Class filtroClass = filtro.getClass();

                Method[] filtroMethods = filtroClass.getDeclaredMethods();
                for(Method filtroMethod : filtroMethods){
                    String nameMethod = filtroMethod.getName();
                    if(nameMethod.startsWith("get") || nameMethod.startsWith("is")){
                        Object value = filtroMethod.invoke(filtro, (Object[]) null);
                        if(value != null){
                            Method originalMethod = originalClass.getDeclaredMethod(nameMethod, (Class[]) null);
                            Object originalValue = originalMethod.invoke(original, (Object[]) null);

                            if(originalValue instanceof String){
                                if(!((String)value).equalsIgnoreCase((String)originalValue)){
                                    result = false;
                                    break;
                                }
                            }else{
                                if(!value.equals(originalValue)){
                                    result = false;
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return result;
    }

    public static void copyProperties(pe.gob.osinergmin.bean.common.UnidadOperativa source, pe.gob.osinergmin.bean.common.UnidadOperativa destination){
        final String GET = "get";
        final String SET = "set";
        final String IS = "is";
        try {
            if(source != null && destination != null){
                Class sourceClass = source.getClass();
                Class destinationClass = destination.getClass();

                Method[] sourceMethods = sourceClass.getDeclaredMethods();
                for(Method sourceMethod : sourceMethods){
                    String nameMethod = sourceMethod.getName();
                    if(nameMethod.startsWith(GET)){
                        String setter = SET.concat(nameMethod.substring(GET.length(), nameMethod.length()));
                        Method setMethod = destinationClass.getDeclaredMethod(setter, sourceMethod.getReturnType());
                        setMethod.invoke(destination, sourceMethod.invoke(source, (Class[]) null));
                    }
                    if(nameMethod.startsWith(IS)){
                        String setter = SET.concat(nameMethod.substring(IS.length(), nameMethod.length()));
                        Method setMethod = destinationClass.getDeclaredMethod(setter, sourceMethod.getReturnType());
                        setMethod.invoke(destination, sourceMethod.invoke(source, (Class[]) null));
                    }
                }
            }
        } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    public static void writeExternalFile(Context context, String fileName, String data){
        try{
            File root = new File(Environment.getExternalStorageDirectory(), PuntoControlConstants.APP_DATA_DIR);
            if (!root.exists()) {
                boolean resultMkdir = root.mkdirs();
                Log.d("<PuntoControlUtils:deleteExternal:mkdir>", String.valueOf(resultMkdir));
            }
            File file = new File(root, fileName + PuntoControlConstants.DATA_FILE_EXT);
            if(file.exists()){
                deleteExternalFile(context, fileName + PuntoControlConstants.DATA_FILE_EXT);
                //boolean result = file.delete();
                //Log.d("<PuntoControlUtils:writeExternalFile:deleteFile>", String.valueOf(result));
            }
            getStorage(context).createFile(PuntoControlConstants.APP_DATA_DIR, fileName + PuntoControlConstants.DATA_FILE_EXT, data);
            /*
            FileWriter fileWriter = new FileWriter(file);
            fileWriter.append(data);
            fileWriter.flush();
            fileWriter.close();*/
            //Toast.showToast(context, "Archivo Almacenado", Toast.LENGTH_SHORT).show();
        }catch(Exception e){
            Toast.makeText(context, e.getMessage(), Toast.LENGTH_SHORT).show();
        }
    }

    public static String readExternalFile(Context context, String fileName){
        StringBuilder json = new StringBuilder();
        try{
            File root = new File(Environment.getExternalStorageDirectory(), PuntoControlConstants.APP_DATA_DIR);
            if (!root.exists()) {
                boolean resultMkdir = root.mkdirs();
                Log.d("<PuntoControlUtils:deleteExternal:mkdir>", String.valueOf(resultMkdir));
            }
            File file = new File(root, fileName + PuntoControlConstants.DATA_FILE_EXT);
            if(file.exists()) {
                json.append(getStorage(context).readTextFile(PuntoControlConstants.APP_DATA_DIR, fileName + PuntoControlConstants.DATA_FILE_EXT));
                /*
                FileReader fileReader = new FileReader(file);
                BufferedReader br = new BufferedReader(fileReader);
                String line;

                while ((line = br.readLine()) != null) {
                    json.append(line);
                }*/
                //Toast.showToast(context, "Archivo Leido", Toast.LENGTH_SHORT).show();
            }
        }catch(Exception e){
            Toast.makeText(context, e.getMessage(), Toast.LENGTH_SHORT).show();
        }
        return json.toString();
    }

    public static void deleteExternalFile(Context context, String fileName){
        //boolean result = false;
        File root = new File(Environment.getExternalStorageDirectory(), PuntoControlConstants.APP_DATA_DIR);
        if (!root.exists()) {
            boolean resultMkdir = root.mkdirs();
            Log.d("<PuntoControlUtils:deleteExternal:mkdir>", String.valueOf(resultMkdir));
        }
        File file = new File(root, fileName + PuntoControlConstants.DATA_FILE_EXT);
        if(file.exists()) {
            getStorage(context).deleteFile(PuntoControlConstants.APP_DATA_DIR, fileName + PuntoControlConstants.DATA_FILE_EXT);
            //result = file.delete();
        }
        Log.d("<PuntoControlUtils:deleteExternalFile:context>", String.valueOf(context));
        //Log.d("<PuntoControlUtils:deleteExternalFile:deleteResult>", String.valueOf(result));
    }

    public static boolean validateConnectivity(Context context){
        ConnectivityManager connectivity = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        if (connectivity != null) {
            NetworkInfo info = connectivity.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
            if (info != null) {
                if (info.isConnected()) {
                    return true;
                }
            }
            info = connectivity.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
            if (info != null) {
                if (info.isConnected()) {
                    return true;
                }
            }
        }
        return false;
    }

    public static String getDateFormatter(Date date) {
        return DateUtils.formatDate(date, PuntoControlConstants.DATE_PATTERN);
    }

    public static String writeDateFromTime(long time) {
        Date fecha = new Date(time);
        return DateUtils.formatDate(fecha, PuntoControlConstants.DATE_PATTERN);
    }

    public static ProgressDialog getProgressDialog(){
        return getProgressDialog(null, null);
    }

    public static ProgressDialog getProgressDialog(Context context, final String message){
        if(PuntoControlConstants.progressDialog == null) {
            PuntoControlConstants.progressDialog = new ProgressDialog(context);
            PuntoControlConstants.progressDialog.setCancelable(false);
        }else{
            if(context != null){
                PuntoControlConstants.progressDialog.dismiss();

                PuntoControlConstants.progressDialog = new ProgressDialog(context);
                PuntoControlConstants.progressDialog.setCancelable(false);
            }else{
                if(message != null && !PuntoControlConstants.EMPTY.equals(message)){
                    ((TextView)PuntoControlConstants.progressDialog.findViewById(R.id.txtLoading)).setText(message);
                }
            }
        }
        PuntoControlConstants.progressDialog.setOnShowListener(new DialogInterface.OnShowListener() {
            @Override
            public void onShow(DialogInterface dialog) {
                PuntoControlConstants.progressDialog.setContentView(R.layout.dialog_progress);
                PuntoControlConstants.progressDialog.getWindow().setGravity(Gravity.CENTER_HORIZONTAL|Gravity.CENTER_VERTICAL);
                ((TextView)PuntoControlConstants.progressDialog.findViewById(R.id.txtLoading)).setText(message);
            }
        });
        return PuntoControlConstants.progressDialog;
    }

    public static void createNewRowTableDetalleSCOP(TableLayout table, SupervisionMovilDetalleSCOP supervisionMovilDetalleSCOP, List<Producto> productoList, Activity activity) {
        Context context = table.getContext();
        TableRow tableRow = new TableRow(context);

        // Se instancian las columnas
        TextView compartimiento = new TextView(context);
        TextView cantidad = new TextView(context);
        TextView producto = new TextView(context);
        TextView superior = new TextView(context);
        TextView inferior = new TextView(context);

        compartimiento.setText(String.valueOf(supervisionMovilDetalleSCOP.getCompartimiento()));
        cantidad.setText(supervisionMovilDetalleSCOP.getCantidad() != null ? String.valueOf(supervisionMovilDetalleSCOP.getCantidad()) : PuntoControlConstants.EMPTY);
        Producto _producto = getProductoFromCodigo(productoList, supervisionMovilDetalleSCOP.getProducto());
        producto.setText(_producto != null ? _producto.getDescripcion() : PuntoControlConstants.EMPTY);
        superior.setText(supervisionMovilDetalleSCOP.getSuperior());
        inferior.setText(supervisionMovilDetalleSCOP.getInferior());

        // Se agregan las columnas a la fila
        tableRow.addView(compartimiento);
        tableRow.addView(cantidad);
        tableRow.addView(producto);
        tableRow.addView(superior);
        tableRow.addView(inferior);

        // Se le agrega el menú contextual
        activity.registerForContextMenu(tableRow);

        // Se agrega la fila a la tabla
        table.addView(tableRow);
    }

    public static void createRefreshRowTableDetalleSCOP(TableLayout table, SupervisionMovilDetalleSCOP supervisionMovilDetalleSCOP, Integer index, List<Producto> productoList, Activity activity) {
        TableRow tableRow = (TableRow)table.getChildAt(index);

        TextView compartimiento = (TextView)tableRow.getChildAt(0);
        TextView cantidad = (TextView)tableRow.getChildAt(1);
        TextView producto = (TextView)tableRow.getChildAt(2);
        TextView superior = (TextView)tableRow.getChildAt(3);
        TextView inferior = (TextView)tableRow.getChildAt(4);

        compartimiento.setText(String.valueOf(supervisionMovilDetalleSCOP.getCompartimiento()));
        cantidad.setText(String.valueOf(supervisionMovilDetalleSCOP.getCantidad()));
        Producto _producto = getProductoFromCodigo(productoList, supervisionMovilDetalleSCOP.getProducto());
        producto.setText(_producto != null ? _producto.getDescripcion() : PuntoControlConstants.EMPTY);
        superior.setText(supervisionMovilDetalleSCOP.getSuperior());
        inferior.setText(supervisionMovilDetalleSCOP.getInferior());

        table.removeViewAt(index);

        activity.registerForContextMenu(tableRow);

        table.addView(tableRow, index);
    }

    private static Producto getProductoFromCodigo(List<Producto> productoList,Integer codigo){
        for(int i = 0; i < productoList.size(); i++){
            Producto producto = productoList.get(i);
            if(codigo != null) {
                if (producto.getCodigo().intValue() == codigo.intValue()) {
                    return producto;
                }
            }
        }
        return null;
    }

    private static Storage getStorage(Context mContext){
        if(PuntoControlConstants.storage == null) {
            if (SimpleStorage.isExternalStorageWritable()) {
                PuntoControlConstants.storage = SimpleStorage.getExternalStorage();
            } else {
                PuntoControlConstants.storage = SimpleStorage.getInternalStorage(mContext);
            }

            SimpleStorageConfiguration configuration = new SimpleStorageConfiguration.Builder().setEncryptContent(PuntoControlConstants.IVX, PuntoControlConstants.SECRET_KEY).build();
            SimpleStorage.updateConfiguration(configuration);
        }
        return PuntoControlConstants.storage;
    }
}